/**
 ******************************************************************************
 * @file       pd_h_gpio.c
 * @author     Chris
 * @since      2023/10/11
 *
 * @brief      Peripheral driver of GPIO.
 ******************************************************************************
 */
#include "pd_h_gpio.h"
#include "stm32g4xx_ll_bus.h"
#include "stm32g4xx_ll_gpio.h"

/** region Declaration and Definition Region */

/** region Variables and Constants Region */
/** endregion Variables and Constants Region */

/** region Function Declaration Region */
/** endregion Function Declaration Region */

/** endregion Declaration and Definition Region */

/** region Public Definition Region */
/**
 * @brief   LED 初始化（PB4 上拉输出）
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_LEDInit(void) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

#ifdef WATER_LED
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2 | LL_GPIO_PIN_3 | LL_GPIO_PIN_4;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#endif

}

/**
 * @brief   有源蜂鸣器（Active Buzzer）初始化（PA6 上拉输出）
 *          只需要使用一个 IO 口，设置为上拉输出模式即可。
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_BuzzerActiveInit(void) {
    // 开启 GPIO 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief   按键初始化（PA0 下拉输入）
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_KeyInit(void) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    LL_GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = LL_GPIO_PIN_0;
    GPIO_InitStructure.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStructure.Pull = LL_GPIO_PULL_DOWN;
    GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_HIGH;

    LL_GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/**
 * @brief   光敏电阻初始化（PA1、PA2）
 *          这里的光敏电阻传感器两个输出：
 *              1. AO(Analog Output，模拟输出)
 *              2. DO(Digital Output，数字输出)
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_LDRInit() {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_1 | LL_GPIO_PIN_2;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief   OLED GPIO 初始化
 *
 * @note    OLED 根据不同的通信协议有不同的初始化方式：
 *          1 SPI：
 *              SDA - PA8
 *              SCK - PA9
 *              CS -- PB12
 *              RS -- PB13
 *              RST - PG10
 *          2 8080
 *              PB
 *          3 I2C
 *              SDA - PA8
 *              SCK - PA9
 * @param   protocol 通信协议：1，SPI；2，8080；3，I2C
 * @retval  无
 */
void PD_H_GPIO_OLEDInit(const uint8_t protocol) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    // I2C 和 SPI 均需要使用 PA8 和 PA9 作用通信引脚
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_8 | LL_GPIO_PIN_9;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_8 | LL_GPIO_PIN_9, SET);

    // SPI
    if (protocol == 1) {
        LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
        LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);

        GPIO_InitStruct.Pin = LL_GPIO_PIN_12 | LL_GPIO_PIN_13;
        LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
        PD_H_GPIO_WriteBit(GPIOB, LL_GPIO_PIN_12 | LL_GPIO_PIN_13, SET);

        GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
        LL_GPIO_Init(GPIOG, &GPIO_InitStruct);
        PD_H_GPIO_WriteBit(GPIOG, LL_GPIO_PIN_10, SET);
    }
}

/**
 * @brief   计次传感器 GPIO 初始化（PA0）
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_CountSensorInit(void) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    PD_H_GPIO_WriteBit(GPIOA, LL_GPIO_PIN_2, SET);
}

/**
 * @brief   定时器 3 的外部触发功能 GPIO 初始化
 *
 * @note    TIM3 的外部触发通道 TIM3_ETR 分别为：
 *             PB3 - AF10
 *             PD2 - AF2
 * @retval  无
 */
void PD_H_GPIO_TIM3_Init(void) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // 复用模式
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_10; // 复用功能引脚 10
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
 * @brief   定时器 4 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_TIM4_Init(void) {
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin =
            LL_GPIO_PIN_6 | LL_GPIO_PIN_7 | LL_GPIO_PIN_8 | LL_GPIO_PIN_9;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // 复用模式
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_2; // 复用功能引脚 2
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
 * @brief   定时器 15 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_TIM15_Init(void) {
    // 开启 GPIOA 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    // 配置 PA2、PA3 的 AF9 为 TIM15_CH1 的输出引脚
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_2 | LL_GPIO_PIN_3;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // 复用功能
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_9; // 指定复用功能序号
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 设置 PA4、5、6、7 为推挽输出，以控制电机芯片的双路输出
    GPIO_InitStruct.Pin =
            LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | LL_GPIO_PIN_6 | LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief   定时器 16 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_TIM16_Init(void) {
    // 开启 GPIOA 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    // 配置 PA6 的 AF1 为 TIM16_CH1 的输出引脚
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // 复用功能
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_1; // 指定复用功能序号
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief   定时器 1 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_TIM8_Init(void) {
    // 开启 GPIOA 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    // 配置 PA6 的 AF1 为 TIM16_CH1 的输出引脚
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // 复用功能
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_5; // 指定复用功能序号
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_10; // 指定复用功能序号
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


/**
 * @brief   ADC1 通道 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_ADC1_Init(void) {
    // 开启 GPIOA 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    // 配置 ADC 对应的 GPIO：PA0   ------> ADC1_IN1
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;           // 模拟输入
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;      // 高速
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; // 输出
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;               // 无上下拉
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;             // 指定复用功能序号
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief   ADC2 通道 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_ADC2_Init(void) {
    // 开启 GPIOA 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

    // 配置 ADC 对应的 GPIO：PA0   ------> ADC1_IN1
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_6 | LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;           // 模拟输入
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;      // 高速
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; // 输出
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;               // 无上下拉
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;             // 指定复用功能序号
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}


/**
 * @brief   USART1 GPIO 初始化
 *
 * @note    无
 * @retval  无
 */
void PD_H_GPIO_USART1_Init(void) {
    // 开启 GPIO 时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    // PB6 - USART1_TX
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;          // 模式：输入、输出、复用、模拟
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;        // 高速
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;   // 输出类型
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;                 // 上下拉
    GPIO_InitStruct.Alternate = LL_GPIO_AF_7;               // 复用功能序号
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // PB7 - USART1_RX
    GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;          // 模式：输入、输出、复用、模拟
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;         // 高速
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;   // 输出类型
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;                 // 上下拉
    GPIO_InitStruct.Alternate = LL_GPIO_AF_7;               // 复用功能序号
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


/**
 * @brief   设置/清零 GPIO 位
 *
 * @note
 * @param GPIOx     @ref GPIO_TypeDef
 * @param GPIO_Pin  GPIO 引脚
 * @param BitVal    要设置的 GPIO 值
 */
void PD_H_GPIO_WriteBit(GPIO_TypeDef *GPIOx, const uint32_t GPIO_Pin,
                        const FlagStatus BitVal) {
    if (BitVal != RESET) {
        GPIOx->BSRR = GPIO_Pin;
    } else {
        GPIOx->BRR = GPIO_Pin;
    }
}

/**
 * @brief  读取指定的输入 GPIO Pin
 *
 * @param GPIOx     @ref GPIO_TypeDef
 * @param GPIO_Pin  要读取的 GPIO 引脚
 * @retval          引脚值
 */
uint8_t PD_H_GPIO_ReadBit(GPIO_TypeDef *GPIOx, const uint32_t GPIO_Pin) {
    return (GPIOx->IDR & GPIO_Pin) != (uint32_t) RESET ? (uint8_t) SET : (uint8_t) RESET;
}

/**
 * @brief   翻转 GPIO 位
 *
 * @note    通过异或操作翻转 GPIO 位
 * @param GPIOx     @ref GPIO_TypeDef
 * @param GPIO_Pin  GPIO 引脚
 */
void PD_H_GPIO_TurnBit(GPIO_TypeDef *GPIOx, const uint32_t GPIO_Pin) {
    GPIOx->ODR ^= GPIO_Pin;
}

/** endregion Public Definition Region */


/** region Private Definition Region */

/** endregion  Private Definition Region  */
